package org.lagou.edu.logSdk.types;

import lombok.Data;
import org.springframework.boot.autoconfigure.kafka.KafkaProperties;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Data
public class OpLogRecord<T> {

    /**
     * 操作记录类型，分为
     * OpLogType.ADD
     * OpLogType.UPDATE
     * OpLogType.DELETE
     */
    private String opLogType;
    private T opLogValue;
    private Diff<T> diff;
    private Map<String, Object> diffDetails;

    public OpLogRecord() {
    }

    public OpLogRecord(String opLogType, T opLogValue, Diff<T> diff) throws IllegalAccessException {
        this.opLogType = opLogType;
        this.opLogValue = opLogValue;
        setDiff(diff);
    }

    public void setDiff(Diff<T> diff) throws IllegalAccessException {
        this.diff = diff;
        doDiffDetails();
    }


    private void doDiffDetails() throws IllegalAccessException {
        // 去除边界条件，保证diff的oldValue和newValue都有效，再进行diff
        if (diff == null) {
            return ;
        }

        if (diff.getOldValue() == null || diff.getNewValue() == null) {
            return ;
        }

        if (!diff.getOldValue().getClass().equals(diff.getNewValue().getClass())) {
            return;
        }

        if (opLogType == OpLogType.UPDATE) {    // 更新操作需要详细计算diff详情
            diffDetails = doDiffDetails(diff.getOldValue(), diff.getNewValue());
        } else {    // 不是更新操作，直接拷贝到map中this的key
            diffDetails.put("this", diff);
        }
    }

    private boolean isPrimitive(Class<?> cls) {
        List<Class> primitiveClasses = new ArrayList<>();

        primitiveClasses.add(Byte.class);
        primitiveClasses.add(Integer.class);
        primitiveClasses.add(Long.class);
        primitiveClasses.add(Short.class);
        primitiveClasses.add(Float.class);
        primitiveClasses.add(Double.class);
        primitiveClasses.add(Character.class);
        primitiveClasses.add(Boolean.class);
        primitiveClasses.add(String.class);


        if (cls.isPrimitive()) {
            return true;
        }

        if (primitiveClasses.indexOf(cls) >= 0) {
            return true;
        }

        return false;
    }

    private boolean isArrayOrList(Class<?> cls) {
        if (cls.isArray() || List.class.isAssignableFrom(cls)) {
            return true;
        }

        return false;
    }

    private Map<String, Object> doDiffDetails(Object oldValue, Object newValue) throws IllegalAccessException {
        HashMap<String, Object> diffHashMap = new HashMap<>();


        for (Field declaredField : oldValue.getClass().getDeclaredFields()) {
            declaredField.setAccessible(true);
            Object oldFieldValue = declaredField.get(oldValue);
            Object newFieldValue = declaredField.get(newValue);

            if (isPrimitive(declaredField.getType())) {


                // 只有当该字段旧值和新值不一样的时候才记录diff
                if (!oldFieldValue.equals(newFieldValue)) {
                    Diff<Object> diff = new Diff<>();
                    diff.setOldValue(declaredField.get(oldValue));
                    diff.setNewValue(declaredField.get(newValue));
                    diffHashMap.put(declaredField.getName(), diff);
                }
                //
            } else if(isArrayOrList(declaredField.getType())) {
                // TODO: 完成字段为数组或List类型的diff比较

            } else { // 当字段类型不为基本类型的时候，递归计算diff
                Map<String, Object> subDiffDetails = doDiffDetails(oldFieldValue, newFieldValue);
                if (subDiffDetails.size() > 0) {
                    diffHashMap.put(declaredField.getName(), subDiffDetails);
                }
            }
        }

        return diffHashMap;

    }

    /**
     * 比较原始类型
     * @param oldValue
     * @param newValue
     * @return
     */
    private Diff<T> doPrimitiveDiff(T oldValue, T newValue) {
        Diff<T> diff = new Diff<>();
        if (oldValue == null || newValue == null) { // 只有旧值和新值都有效时才会进行比较，否者返回null
            return null;
        }


        return null;
    }
}
